﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RuleOfReady.Core.DomainModels.Tiles;

namespace RuleOfReady.Core.DomainModels.Sets
{
    /// <summary>
    /// Object that represents a single Mahjong tile as part of a set
    /// </summary>
    public class MahjongSingleTileSet : MahjongPossibleSet
    {

        #region Public Properties (read-only)

        /// <summary>
        /// (MahjongPossibleSet) Tiles in the one-tile set (yup, there's 1)
        /// </summary>
        public override IEnumerable<MahjongTile> Tiles { get; protected set; }

        /// <summary>
        /// (MahjongPossibleSet) Waiting tiles that can be added to this set to make it into a full set)
        /// </summary>
        public override IEnumerable<MahjongTile> WaitingTiles { get; protected set; }

        /// <summary>
        /// (MahjongPossibleSet) FLAG: Is this a complete set (false)
        /// </summary>
        public override bool CompletedSet { get; protected set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Create a new single tile set, with the given Mahjong tile
        /// </summary>
        /// <param name="tile">tile to make a set out of</param>
        public MahjongSingleTileSet(MahjongTile tile)
        {
            this.Tiles = new[] { tile };
            this.CompletedSet = false;

            MahjongSuitTile suitTile = tile as MahjongSuitTile;
            MahjongHonorTile honorTile = tile as MahjongHonorTile;

            if (suitTile != null)
                this.BuildWaitingTiles(suitTile);
            else if (honorTile != null)
                this.BuildWaitingTiles(honorTile);
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// (MahjongPossibleSet) Add another tile to this single tile to make a new set
        /// </summary>
        /// <param name="addTile"></param>
        /// <returns></returns>
        public override MahjongPossibleSet Add(MahjongTile addTile)
        {
            if (this.WaitingTiles.Contains(addTile))
            {
                if (this.Tiles.Contains(addTile))
                    return new MahjongPair(addTile);
                else
                    //the set is a) a suit tile, and b) addTile is a suit tile as well
                    return new MahjongPartialSequence(
                        Tiles.Concat(Enumerable.Repeat(addTile, 1)).Cast<MahjongSuitTile>());
            }
            else
                return null;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Build the waiting tiles for a single suit tile
        /// </summary>
        /// <param name="tile"></param>
        private void BuildWaitingTiles(MahjongSuitTile tile)
        {            
            IEnumerable<int> validNumbers = Enum.GetValues(typeof(MahjongSuitNumber)).Cast<int>();

            this.WaitingTiles = Enumerable.Range(tile.SuitNumberInt - 2, 5)
                                          .Where(number => validNumbers.Contains(number))
                                          .Select(number => new MahjongSuitTile(tile.SuitType, number));   
        }

        /// <summary>
        /// Build the waiting tiles for a single honor tile
        /// </summary>
        /// <param name="tile"></param>
        private void BuildWaitingTiles(MahjongHonorTile tile)
        {
            this.WaitingTiles = new[] { tile };
        }

        #endregion

    }
}
